import {
  Controller,
  Get,
  Post,
  Body,
  Inject,
  Query,
  UnauthorizedException,
  HttpStatus,
  UseInterceptors,
  UploadedFile,
  BadRequestException,
} from '@nestjs/common';
import { LoginUserDto } from './dto/login-user.dto';
import { RegisterUserDto } from './dto/register-user.dto';
import { UpdateUserPasswordDto } from './dto/update-user-password.dto';
import { UserDetailVo } from './vo/user-info.vo';
import { UpdateUserDto } from './dto/update-user.dto';
import { LoginUserVo } from './vo/login-user.vo';
import { RefreshTokenVo } from './vo/refresh-token.vo';
import { UserListVo } from './vo/user-list.vo';
import { UserService } from './user.service';
import { EmailService } from 'src/email/email.service';
import { RedisService } from 'src/redis/redis.service';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import {
  RequireLogin,
  RequirePermission,
  UserInfo,
} from 'src/custom.decorator';
import { generateParseIntPipe } from 'src/utils';
import {
  ApiQuery,
  ApiTags,
  ApiResponse,
  ApiBody,
  ApiBearerAuth,
} from '@nestjs/swagger/dist';
import { FileInterceptor } from '@nestjs/platform-express';
import * as path from 'path';
import { storage } from 'src/file-storage';

interface UserInfo {
  id: number;
  username: string;
  email: string;
  roles: string[];
  permissions: string[];
}

@ApiTags('用户管理模块')
@Controller('user')
export class UserController {
  @Inject(EmailService)
  private readonly emailService: EmailService;

  @Inject(RedisService)
  private readonly redisService: RedisService;

  @Inject(JwtService)
  private readonly JwtService: JwtService;

  @Inject(ConfigService)
  private readonly configService: ConfigService;

  constructor(private readonly userService: UserService) {}
  // 生成token的方法
  async handleGenerateToken(userInfo: UserInfo) {
    const accessToken = await this.JwtService.sign(
      {
        id: userInfo.id,
        username: userInfo.username,
        email: userInfo.email,
        roles: userInfo.roles,
        permissions: userInfo.permissions,
      },
      {
        expiresIn:
          this.configService.get('jwt_access_token_expires_time') || '30m',
      },
    );
    const refreshToken = await this.JwtService.sign(
      {
        id: userInfo.id,
      },
      {
        expiresIn:
          this.configService.get('jwt_refresh_token_expres_time') || '7d',
      },
    );
    return { accessToken, refreshToken };
  }

  @ApiQuery({
    name: 'email',
    type: String,
    description: '邮箱',
    required: true,
    example: 'xxx@xxx.com',
  })
  @ApiResponse({
    status: HttpStatus.OK,
    type: String,
    description: '发送成功',
  })
  @Get('register-captcha') // 获取注册邮箱验证码
  async registerCaptcha(@Query('email') email: string) {
    const code = Math.floor(Math.random() * 1000000).toString();
    // 保存到redis中，设置过期时间为5分钟
    await this.redisService.set(`captcha_${email}`, code, 5 * 60);
    // 发送邮件
    await this.emailService.sendMail({
      to: email,
      subject: '注册验证码',
      html: `<p>您的注册验证码为：${code}</p>`,
    });
    return '发送成功';
  }

  // 用户注册
  @ApiBody({ type: RegisterUserDto })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '验证码已过期/验证码错误/用户已存在',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '注册成功/失败 ',
    type: String,
  })
  @Post('register')
  register(@Body() registerUser: RegisterUserDto) {
    return this.userService.register(registerUser);
  }

  @Get('init-data')
  async initData() {
    await this.userService.initData();
    return 'done';
  }

  // 用户登录
  @ApiBody({ type: LoginUserDto })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '用户名或密码错误',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '登录成功',
    type: LoginUserVo,
  })
  @Post('login')
  async login(@Body() loginuUser: LoginUserDto) {
    const vo = await this.userService.login(loginuUser, false);
    const { accessToken, refreshToken } = await this.handleGenerateToken(
      vo.userInfo,
    );
    vo.accessToken = accessToken;
    vo.refreshToken = refreshToken;
    return vo;
  }

  // 管理员登录
  @ApiBody({ type: LoginUserDto })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '用户名或密码错误',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '登录成功',
    type: LoginUserVo,
  })
  @Post('admin/login')
  async adminLogin(@Body() loginuUser: LoginUserDto) {
    const vo = await this.userService.login(loginuUser, true);
    const { accessToken, refreshToken } = await this.handleGenerateToken(
      vo.userInfo,
    );
    vo.accessToken = accessToken;
    vo.refreshToken = refreshToken;
    return vo;
  }

  // 刷新用户token
  @ApiQuery({
    name: 'refresh_token',
    type: String,
    description: '刷新token',
    required: true,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '登录已过期，请重新登录',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '刷新成功',
    type: RefreshTokenVo,
  })
  @Get('refresh')
  async refresh(@Query('refresh_token') oldRefreshToken: string) {
    try {
      const data = await this.JwtService.verify(oldRefreshToken);
      const user = await this.userService.findUserById(data.id, false);
      const { accessToken, refreshToken } = await this.handleGenerateToken(
        user,
      );
      const vo = new RefreshTokenVo();
      vo.accessToken = accessToken;
      vo.refreshToken = refreshToken;
      return vo;
    } catch (e) {
      throw new UnauthorizedException('登录已过期，请重新登录');
    }
  }

  // 刷新管理员token
  @ApiQuery({
    name: 'refresh_token',
    type: String,
    description: '刷新token',
    required: true,
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: '登录已过期，请重新登录',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '刷新成功',
    type: RefreshTokenVo,
  })
  @Get('admin/refresh')
  async refreshAdmin(@Query('refresh_token') oldRefreshToken: string) {
    try {
      const data = await this.JwtService.verify(oldRefreshToken);
      const user = await this.userService.findUserById(data.id, true);
      const { accessToken, refreshToken } = await this.handleGenerateToken(
        user,
      );
      return {
        accessToken,
        refreshToken,
      };
    } catch (e) {
      throw new UnauthorizedException('登录已过期，请重新登录');
    }
  }

  @ApiBearerAuth()
  @ApiResponse({
    status: HttpStatus.OK,
    description: '获取用户信息成功',
    type: UserDetailVo,
  })
  @Get('info')
  @RequireLogin()
  async info(@UserInfo('id') userId: number) {
    const user = await this.userService.findUserDetailById(userId);
    const vo = new UserDetailVo();
    vo.id = user.id;
    vo.email = user.email;
    vo.username = user.username;
    vo.headPic = user.headPic;
    vo.phoneNumber = user.phoneNumber;
    vo.nickName = user.nickName;
    vo.createTime = user.createTime;
    vo.isFrozen = user.isFrozen;
    return vo;
  }

  @ApiBody({ type: UpdateUserPasswordDto })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '验证码已过期/验证码错误',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '修改成功/失败',
    type: String,
  })
  @Post(['update_password', 'admin/update_password'])
  async updatePassword(@Body() dto: UpdateUserPasswordDto) {
    return await this.userService.updatePassword(dto);
  }

  @Get('update_password/captcha') // 获取注册邮箱验证码
  async updatePasswordCaptcha(@Query('email') email: string) {
    const code = Math.floor(Math.random() * 1000000).toString();
    // 保存到redis中，设置过期时间为5分钟
    await this.redisService.set(`update_password_${email}`, code, 5 * 60);
    // 发送邮件
    await this.emailService.sendMail({
      to: email,
      subject: '修改密码验证码',
      html: `<p>您的更改密码验证码为：${code}</p>`,
    });
    return '发送成功';
  }

  @ApiBearerAuth()
  @ApiBody({ type: UpdateUserDto })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '验证码已过期/验证码错误',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '修改成功/失败',
    type: String,
  })
  @Post('update')
  @RequireLogin()
  async update(
    @Body() updateUserDto: UpdateUserDto,
    @UserInfo('id') userId: number,
  ) {
    await this.userService.update(userId, updateUserDto);
  }

  @ApiBearerAuth()
  @ApiResponse({
    status: HttpStatus.OK,
    type: String,
    description: '发送成功',
  })
  @RequireLogin()
  @Get('update_user/captcha') // 获取修改用户信息验证码
  async updateUserCaptcha(@UserInfo('email') email: string) {
    console.log(email);
    const code = Math.floor(Math.random() * 1000000).toString();
    // 保存到redis中，设置过期时间为5分钟
    await this.redisService.set(`update_user_${email}`, code, 5 * 60);
    // 发送邮件
    await this.emailService.sendMail({
      to: email,
      subject: '修改用户信息验证码 ',
      html: `<p>您的修改用户信息验证码为：${code}</p>`,
    });
    return '发送成功';
  }

  @ApiBearerAuth()
  @ApiQuery({
    name: 'id',
    type: Number,
    description: '用户id',
    required: true,
  })
  @Get('freeze')
  async freeze(@Query('id') id: number) {
    await this.userService.freezeUserById(id);
    return '冻结成功';
  }

  @ApiBearerAuth()
  @ApiQuery({
    name: 'pageNumber',
    description: '第几页',
    type: Number,
  })
  @ApiQuery({
    name: 'pageSize',
    description: '每页多少条',
    type: Number,
  })
  @ApiQuery({
    name: 'username',
    description: '用户名',
    type: Number,
  })
  @ApiQuery({
    name: 'nickName',
    description: '昵称',
    type: Number,
  })
  @ApiQuery({
    name: 'email',
    description: '邮箱地址',
    type: Number,
  })
  @ApiResponse({
    type: UserListVo,
    description: '用户列表',
  })
  @Get('list')
  async list(
    @Query('pageNumber', generateParseIntPipe('pageNumber'))
    pageNumber,
    @Query('pageSize', generateParseIntPipe('pageSize'))
    pageSize: number,
    @Query('username') username: string,
    @Query('nickName') nickName: string,
    @Query('email') email: string,
  ) {
    const data = await this.userService.findUsersByPage(
      pageNumber,
      pageSize,
      username,
      nickName,
      email,
    );
    const vo = new UserListVo();
    vo.users = data.users;
    vo.count = data.count;
    return vo;
  }

  @Post('upload')
  @UseInterceptors(
    FileInterceptor('file', {
      dest: 'uploads',
      limits: {
        fileSize: 3 * 1024 * 1024,
      },
      storage: storage,
      fileFilter(req, file, callback) {
        const extname = path.extname(file.originalname);
        if (['.png', '.jpg', '.gif'].includes(extname)) {
          callback(null, true);
        } else {
          callback(new BadRequestException('只能上传图片'), false);
        }
      },
    }),
  )
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    console.log('file', file);
    return file.path;
  }

  @Get('aaa')
  @RequireLogin()
  async aaa() {
    return 'aaaa';
  }

  @Get('ccc')
  @RequireLogin()
  @RequirePermission('ccc')
  async ccc() {
    return 'ccc';
  }

  @Get('ddd')
  @RequireLogin()
  async ddd(@UserInfo('username') username: string, @UserInfo() user: any) {
    console.log(username);
    console.log(user);
    return username;
  }
}
